/*** Some infos ***/
uniform vec2 srlViewPort;
uniform int srlDiffuseEnabled;
uniform int srlParallaxEnabled;
uniform int srlColorEn;
uniform int srlLightEn;
uniform int srlRepeatType;
uniform int srlNormalMapping;
uniform vec4 lightPosition;

varying vec4 srlPosition;
varying vec4 srlLight;
varying vec4 srlNormal;
varying vec4 srlCamera;
varying vec4 srlSun;

// Tangent space
varying vec3 T;
varying vec3 B;
varying vec3 N;
varying mat3 TBN;

/*** Textures & materials ***/
uniform sampler2D srlTextureDiffuse;
uniform sampler2D srlTextureNormal;
uniform sampler2D srlTextureGloss;
uniform sampler2D srlTextureBump;
uniform sampler2D srlTextureHeight;
uniform int		  srlIsLight;

/*** Terrain texture ***/
uniform sampler2D srlTexture1;
uniform sampler2D srlTexture1A;
uniform sampler2D srlTexture2;
uniform sampler2D srlTexture2A;
uniform sampler2D srlTexture3;
uniform sampler2D srlTexture3A;

/*** Radial Blur ***/
uniform int srlRadialBlur;
uniform vec2 srlRadialBlurLightPos;
uniform sampler2D srlRadialBlurMap;

uniform int srlTextureType;

#define SRL_REPEAT		2
#define	SRL_ONCE		1
#define SRL_SCALE		0

struct srlMaterial {
	sampler2D spec;
	sampler2D diffuse;
	sampler2D normal;
	sampler2D height;
};

vec3 GetParallaxCoord(sampler2D HeightMap, vec3 coord, vec3 viewVector, float scale=0.04, float bios=-0.02);

float GetDiffuse(vec4 N, vec3 L);
float GetSpecular(vec4 Cam, vec4 Pos, vec3 N, vec4 L);
float GetAttenuation(vec4 Pos, vec4 N, vec3 L, float Radius);

float GetPointLight(vec4 Cam, vec4 Pos, vec4 N, vec4 Light, float Radius);
float GetPointLight(vec4 Cam, vec4 Pos, vec2 Coord, srlMaterial mat, vec4 N, vec4 Light, float Radius);
float GetPointLight(vec4 Cam, vec4 Pos, vec4 N, vec4 L, float Radius);
float GetPointLight(vec4 Cam, vec4 Pos, vec2 Coord, srlMaterial mat, vec4 N, vec4 L, float Radius);

float GetDirectionalLight(vec4 N, vec3 L, float D);



vec3 ScalePos(vec2 Pos, vec2 Size);
vec4 GetTextureWithAlpha(sampler2D Tex, sampler2D Alpha, vec2 Coord, vec2 CoordAlpha, bool Inverse=false);

vec4 RadialBlurC(sampler2D tex, vec2 center, vec2 position=gl_TexCoord[0].st, int number=1.0, float density=1.0, float decay=1.0, float weight=5.0, float exposure=0.01);
vec4 RadialBlur(sampler2D tex, vec2 center, vec2 position, float number=10.0, float density=1.5);

void main() {
		vec4 FragColor; // <--- Final Color
		vec3 TexCoord;
		
		// Material
		srlMaterial srlMat;
		srlMat.spec = srlTextureGloss;
		srlMat.diffuse = srlTextureDiffuse;
		srlMat.normal = srlTextureNormal;
		srlMat.height = srlTextureHeight;
		
		// Repeat Coord or Scale
		if(srlRepeatType == 2 )
			TexCoord = ScalePos(gl_TexCoord[0].st, vec2(1.0, 1.0));
        else
        	TexCoord = gl_TexCoord[0];
        	
        	
		// Color
        if(srlColorEn == 1)
        	FragColor = gl_Color;
        else
        	FragColor = vec4(1.0, 1.0, 1.0, 1.0);
        
        
        // Parallax
        if(srlParallaxEnabled==1)
        	TexCoord = GetParallaxCoord(srlTextureHeight, TexCoord, normalize(gl_TexCoord[1]));

        	
        // Texture
        if(srlDiffuseEnabled == 1)
            FragColor *= texture2D(srlTextureDiffuse, TexCoord );
            
            
        else if(srlTextureType == 2) {
            vec3 texPos = ScalePos(gl_TexCoord[0].st, vec2(50.0, 50.0));
            FragColor = GetTextureWithAlpha(srlTexture1, srlTexture1A, texPos, gl_TexCoord[0].st, true) * GetTextureWithAlpha(srlTexture2, srlTexture1A, texPos, gl_TexCoord[0].st);

        }
        else if(srlTextureType == 3) {
                FragColor = texture2D(srlTextureDiffuse, gl_TexCoord[0].st);
        }
        
        
        
        // Normal Mapping
        if(srlNormalMapping == 1)
        	srlNormal = normalize( srlNormal + texture2D(srlTextureNormal, TexCoord) );
        
        
        
        // Light
        if(srlLightEn == 1)
        	FragColor *= GetDirectionalLight(srlNormal, srlSun - srlCamera, 20.0);
        /*if(srlParallaxEnabled==1)	
        	FragColor = vec4(    normalize(gl_TexCoord[1]));*/
		//gl_FragData[0] = FragColor;
		gl_FragColor = FragColor;
		
		/*if(srlIsLight == 1)
			gl_FragData[1] = vec4(1.0,1.0,1.0,1.0);
		else
			gl_FragData[1] = vec4(0.0,0.0,0.0,1.0);*/
}




/**** Material ****/
vec3 GetParallaxCoord(sampler2D HeightMap, vec3 coord, vec3 viewVector, float scale, float bios) {
	float height = scale * texture2D(HeightMap, coord).r + bios;
	return (height * viewVector) + coord;
}




/**** Ligth Functions ***/
float GetDiffuse(vec4 N, vec3 L) {
        float Difuse = dot(N.xyz, L);
        return Difuse;
}

float GetSpecular(vec4 Cam, vec4 Pos, vec4 N, vec3 L) {
        /* vec3 C = Pos.xyz - Cam.xyz;
        vec3 CR = N.xyz - C;
        float Spec = max(0.0, dot(CR, L)); */
        
        /*vec3 C = Pos.xyz - Cam.xyz;
        vec3 R = -2.0 * N.xyz * dot(N.xyz, L) + L;
        R = normalize(R);
        C = normalize(C);
        float Spec = max(0.0, dot(R, C));*/
        
        vec3 C = normalize(Pos.xyz - Cam.xyz);
		vec3 H = C - L;
		float Spec = max(0.0, dot(N.xyz, H));
        return Spec;
}

float GetAttenuation(vec4 Pos, vec4 N, vec3 L, float Radius) {
        float Attenuation = max(0.0, 1.0 - (length(L) / Radius));
        return Attenuation;
}

float GetPointLight(vec4 Cam, vec4 Pos, vec4 N, vec3 L, float Radius) {
        return
                (GetDiffuse(N, L) +
                GetSpecular(Cam, Pos, N, L)) *
                GetAttenuation(Pos, N, L, Radius);
}

float GetPointLight(vec4 Cam, vec4 Pos, vec2 Coord, srlMaterial mat, vec4 N, vec3 L, float Radius) {
        return
                (GetDiffuse(N, L) +
                (GetSpecular(Cam, Pos, N, L) * (texture2D(mat.spec, Coord).r+2.0))) *
                GetAttenuation(Pos, N, L, Radius);
}
float GetPointLight(vec4 Cam, vec4 Pos, vec4 N, vec4 Light, float Radius) {
		return GetPointLight(Cam, Pos, N, Light.xyz - Pos.xyz, Radius);
}
float GetPointLight(vec4 Cam, vec4 Pos, vec2 Coord, srlMaterial mat, vec4 N, vec4 Light, float Radius) {
		return GetPointLight(Cam, Pos, Coord, mat, N, Light.xyz - Pos.xyz, Radius);
}

float GetDirectionalLight(vec4 N, vec3 L, float D) {
		return GetDiffuse(N, L) / D;
}



/**** Terrain & Texturing Functions ****/
vec3 ScalePos(vec2 Pos, vec2 Size) {
        return vec3(fract(gl_TexCoord[0].st * Size.xy), 1.0);
}
vec4 GetTextureWithAlpha(sampler2D Tex, sampler2D Alpha, vec2 Coord, vec2 CoordAlpha, bool Inverse) {
        if(Inverse)
                return (texture2D(Tex, Coord) + 1.0 - texture2D(Alpha, CoordAlpha));
        else
                return (texture2D(Tex, Coord) + texture2D(Alpha, CoordAlpha));
}





/**** Radial Blur for the Sun ****/
vec4 RadialBlurC(sampler2D tex, vec2 center, vec2 position, int number, float density, float decay, float weight, float exposure) {
        vec4 finalColor = vec4(0.0);
        vec2 toLight = position - center;
        toLight /= float(number) * density;

        vec2 pos = position;
        vec4 sample;
        float dec = 1.0;
        
        for(int i = 0; i < number ; i++) {
                pos -= toLight;
                sample = texture2D(tex, pos);
                
                sample *= dec * weight;
                finalColor += sample;
                dec *= decay;
        }
        finalColor *= exposure;
        return finalColor;
}
vec4 RadialBlur(sampler2D tex, vec2 center, vec2 position, float number, float density) {

        vec4 c = vec4(0.0);
        float scale = 0.0;

        for(float i = 0.0; i < number; i++)     {
                c += texture2D(tex, (position * scale) + 0.5);
                scale += density;
        }

        c /= number;
        return c;
};


/**** Fog ****/
vec4 Fog(vec4 FColor, vec4 Color, vec4 Pixel) {
        const float LOG2 = 1.442695;
        float z = Pixel.z / Pixel.w;
        float fogFactor = exp2( -gl_Fog.density * 
                                   gl_Fog.density * z * z * 
                                   LOG2 );
        fogFactor = clamp(fogFactor, 0.0, 1.0);

        return mix(Color, FColor, fogFactor );
}

